package cn.wizzer.app.web.modules.controllers.open;

import cn.wizzer.app.user.modules.models.User;
import cn.wizzer.app.user.modules.models.UserLog;
import cn.wizzer.app.user.modules.models.constant.RedisKey;
import cn.wizzer.app.user.modules.models.enums.PhoneCodeEnum;
import cn.wizzer.app.user.modules.services.UserLogService;
import cn.wizzer.app.user.modules.services.UserService;
import cn.wizzer.app.web.commons.ulog.annotation.ULog;
import cn.wizzer.app.web.commons.utils.SMSUtil;
import cn.wizzer.app.web.commons.utils.SmsCHMResult;
import cn.wizzer.app.web.commons.utils.TokenUtil;
import cn.wizzer.framework.base.model.enums.BizExceptionEnum;
import cn.wizzer.framework.util.Id;
import cn.wizzer.framework.util.Result;
import cn.wizzer.framework.util.param.ParamVerify;
import com.alibaba.dubbo.config.annotation.Reference;
import org.nutz.dao.Cnd;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.Mvcs;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;

import java.util.List;

/**
 * 手机验证码
 *
 * @author .
 */

@IocBean
@At("/open/phone")
public class APiPhoneController {
    private static final Log log = Logs.get();

    @Inject
    private RedisService redisService;

    @Inject
    private TokenUtil tokenUtil;

    @Inject
    @Reference
    private UserService userService;

    @Inject
    @Reference
    private UserLogService userLogService;

    @At
    @Ok("json")
    @ULog(tag = "发送手机验证码", msg = "手机号前缀: ${phonePrefix}, 手机号: ${phone}, 操作类型: ${type}")
    public Result sendCode(@ParamVerify(required = true, name = "phonePrefix") String phonePrefix,
                           @ParamVerify(required = true, name = "phone") String phone,
                           @ParamVerify(required = true, name = "type") String type) {
        phonePrefix = phonePrefix.replaceAll("\\+", "").trim();
        phone = phone.trim().replaceFirst("^0*", "");

        int num = userService.count(Cnd.where("phonePrefix", "=", phonePrefix).and("phone", "=", phone));
        String appid = Mvcs.getReq().getHeader("appid");
        if (PhoneCodeEnum.REGISTER.VALUE.equals(type)) {
            // 注册时需要验证码
            String ip = Lang.getIP(Mvcs.getReq());
            // 一个IP每天限制发5条短信
            List<UserLog> listLog = userLogService.listToday("发送手机验证码", ip);
            if (listLog.size() > 5) {
                return Result.error(BizExceptionEnum.REGISTER_IP_FREQUENTLY);
            }
        }
        // 注册时，如果手机号已被别人注册，不发送验证码
        if (PhoneCodeEnum.REGISTER.VALUE.equals(type) && num > 0) {
            return Result.error(BizExceptionEnum.PHONE_REGISTERED);
        }
        // 修改手机号码时，如果该手机号码已被别人注册，则不发送验证码
        else if (PhoneCodeEnum.UPDATEPHONE.VALUE.equals(type) && num > 0) {
            return Result.error(BizExceptionEnum.PHONE_REGISTERED);
        }
        // 重置登录密码时，如果手机号码不存在，则不发送验证码
        else if (PhoneCodeEnum.RESETLOGINPWD.VALUE.equals(type) && num == 0) {
            return Result.error(BizExceptionEnum.PHONE_UNREGISTERED);
        }
        // 重置交易密码时，验证登录状态
        else if (PhoneCodeEnum.RESETTRADEPWD.VALUE.equals(type)) {
            if (!tokenUtil.verifyToken(appid, Mvcs.getReq().getHeader("token"))) {
                return Result.error(BizExceptionEnum.UN_LOGIN);
            }
            // 查该用户已绑定的手机号，如果和传来的参数的不相同，返回错误
            User user = userService.fetch(appid);
            if (!(user.getPhonePrefix().equals(phonePrefix) && user.getPhone().equals(phone))) {
                return Result.error(BizExceptionEnum.ILLEGAL_OPERATION);
            }
        }
        String key = PhoneCodeEnum.FIX + type + ":" + phonePrefix + "&" + phone;
        // 根据需求，如果用户输入错手机号，发送成功后一分钟之后可以再次发送。但在一分钟内，不能再次发送。
        String value = redisService.get(key);
        if (Strings.isNotBlank(value) && redisService.ttl(key) > 240) {
            return Result.error(BizExceptionEnum.DO_NOT_GET_CODES_FREQUENTLY);
        }
        // 生成验证码
        String verifyCode = Id.createVerifyCode();
        // 发送验证码根据返回状态判断是否成功
        SmsCHMResult result = SMSUtil.sendCHM(phonePrefix + phone, verifyCode);
        if (0 == result.getStatus()) {
            // 加入redis中用以查询验证 过期时间10分钟
            redisService.setex(key, RedisKey.M_10, verifyCode);
            log.info("手机验证码发送成功。操作类型：" + type + "。号码前缀：" + phonePrefix + "。号码：" + phone + "。result：" + result);
            return Result.success(BizExceptionEnum.SEND_CODE_SUCCESS);
        } else {
            log.error("手机验证码发送失败。操作类型：" + type + "。号码前缀：" + phonePrefix + "。号码：" + phone + "。result：" + result);
            // 给用户返回可见的错误：-2：IP访问受限。-9：号码异常。
            if (-9 == result.getStatus()) {
                return Result.error(BizExceptionEnum.INVALID_PHONE_NUMBER);
            } else if (-2 == result.getStatus()) {
                return Result.error(BizExceptionEnum.DO_NOT_GET_CODES_FREQUENTLY);
            } else {
                return Result.error(BizExceptionEnum.SEND_CODE_FAIL);
            }
        }
    }

}
